home *** CD-ROM | disk | FTP | other *** search
- /*
- * nfstrace main module
- * release 0.9
- *
- * Copyright 1991 Matt Blaze.
- * May be freely reproduced for non-commerical use.
- * All other rights, including use for direct commerical advantage or
- * use in a commerical product, are reserved by the author.
- *
- * bug reports, etc -> mab@cs.princeton.edu
- *
- * This version does NOT include the handle->name translation.
- * That version works, but is rough enough that it is not included in
- * the general distribution. If you have a use for it, contact the author.
- */
-
- #include<sys/types.h>
- #include<sys/stat.h>
- #include <stdio.h>
- #include <strings.h>
- #include "nfsstuff.h"
-
- #define HSIZE 65599
- #define MAXNF 20000
- static int nf=0;
- char comp[64] = "/usr/ucb/compress -c";
-
- typedef struct clirec {
- char name[64]; /* of client */
- int direction; /* 0==read, else write */
- int zeroaccessed; /* zeroth byte accessed yet? */
- int readcount; /* total bytes accessed */
- int writecount; /* bytes written */
- unsigned long startsecs; /* time operation started */
- unsigned long startusecs;
- unsigned long lastsecs; /* last access */
- unsigned long lastusecs;
- struct clirec *nextcli; /* in hash table */
- struct clirec *nextpend, *prevpend; /* list of pending r/w ops */
- struct file *file;
- } clirec;
-
- typedef struct file {
- char key[64]; /* server:handle */
- int mode;
- int uid;
- int size;
- struct clirec *clients;
- struct file *next;
- } file;
-
-
- clirec *pending; /* list of clients w/ pending read or write ops */
-
- file *table[HSIZE]; /* the file handle hash table */
-
- #define NAME "nfs.out"
-
- int curfile=0;
- int cursecs=0;
- int curusecs=0;
- int lasttimedone=0;
- int oplen=135;
-
- FILE *fd;
-
- char *firstpart();
- char *lastpart();
- clirec *getcli();
- file *getfile();
- unsigned long hashval();
- char *mkkey();
- char *Malloc();
- static int n=1;
-
-
-
-
- int nfs_null(),
- nfs_getattr(),
- nfs_setattr(),
- nfs_root(),
- nfs_lookup(),
- nfs_readlink(),
- nfs_read(),
- nfs_writecache(),
- nfs_write(),
- nfs_creat(),
- nfs_remove(),
- nfs_rename(),
- nfs_link(),
- nfs_symlink(),
- nfs_mkdir(),
- nfs_rmdir(),
- nfs_readdir(),
- nfs_statfs();
-
- int (*nfs_proc[])() = {
- nfs_null, /* 0 */
- nfs_getattr, /* 1 */
- nfs_setattr, /* 2 */
- nfs_root, /* 3 */
- nfs_lookup, /* 4 */
- nfs_readlink, /* 5 */
- nfs_read, /* 6 */
- nfs_writecache, /* 7 */
- nfs_write, /* 8 */
- nfs_creat, /* 9 */
- nfs_remove, /* 10 */
- nfs_rename, /* 11 */
- nfs_link, /* 12 */
- nfs_symlink, /* 13 */
- nfs_mkdir, /* 14 */
- nfs_rmdir, /* 15 */
- nfs_readdir, /* 16 */
- nfs_statfs /* 17 */
- };
-
-
- char template[64];
- int compress=0;
- int outflag=0;
- int filesize=5000;
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- int i;
- char *flag;
- char *c;
- char *pn;
-
- strcpy(template,NAME);
- pn=argv[0];
- while (--argc) {
- if (**++argv == '-') { /* flag */
- for (flag = ++*argv; *flag; flag++) {
- switch (*flag) {
- case '-': /* just write to stdout */
- outflag++;
- fd=stdout;
- break;
- case 'c': /* compress output */
- compress++;
- break;
- case 's': /* size of output files */
- case 't': /* name template*/
- case 'n': /* file number */
- case 'w': /* time to wait for close */
- case 'z': /* name of compress cmd */
- enq(*flag);
- break;
- default:
- usage(pn);
- exit(-1);
- }
- }
- } else {
- switch (deq()) {
- case -1:
- usage();
- exit(-1);
- case 's':
- filesize=atoi(*argv);
- break;
- case 't':
- strcpy(template,*argv);
- break;
- case 'n':
- curfile=atoi(*argv);
- break;
- case 'w':
- oplen=atoi(*argv);
- break;
- case 'z':
- strcpy(comp,*argv);
- break;
- default: /* should never happen */
- fprintf(stderr,"Internal error\n");
- exit(-2);
- }
- }
-
- }
- if ((deq() != -1)) {
- usage(pn);
- exit(-1);
- }
- for (i=0; i<HSIZE; i++)
- table[i]=NULL;
- if (!outflag)
- outopen();
- yyparse();
- cursecs+=500;
- checkall();
- }
-
-
- usage(s)
- char *s;
- {
- fprintf(stderr,
- "usage: %s [--] [-c] [-t template] [-s size] [-n seqnum] [-w timeout] [-z filt]\n",s);
- }
-
-
- #define QS 10
- struct {
- int data[QS];
- int head;
- int tail;
- } argq = {{0},0,0};
-
- enq(f)
- char f;
- {
- argq.tail++;
- argq.tail %= QS;
- if (argq.head==argq.tail) {
- fprintf(stderr,"Can't deal with this\n");
- exit(-2);
- }
- argq.data[argq.tail]=f;
- }
-
- deq()
- {
- if (argq.head==argq.tail)
- return -1;
- argq.head++;
- argq.head %= QS;
- return(argq.data[argq.head]);
- }
-
- #define CHECKFREQ 65
-
- outopen()
- {
- char buf[64];
- if (compress) {
- sprintf(buf,"%s>%s.%05d.Z",comp,template,curfile);
- if ((fd=popen(buf,"w")) == NULL) {
- perror(buf);
- exit(1);
- }
- } else {
- sprintf(buf,"%s.%05d",template,curfile);
- if((fd=fopen(buf,"w"))==NULL) {
- perror(buf);
- exit(1);
- }
- }
- }
-
- do_operation()
- {
- if (l.stat == 0)
- return; /* we dont care about failures */
- if (l.op>=RFS_NPROC)
- return; /* should never happen */
- if (!validtime(l.time))
- return; /* should never happen */
- cursecs=atoi(firstpart(l.time));
- curusecs=atoi(lastpart(l.time));
- if ((cursecs-lasttimedone)>CHECKFREQ) {
- checkall();
- lasttimedone=cursecs;
- }
- if (!outflag &&(n>filesize)) {
- switchfile();
- n=1;
- }
- (*nfs_proc[l.op])();
- }
-
- switchfile()
- {
- char buf[64];
-
- cursecs += 500;
- checkall();
- cursecs -= 500;
- closefile(fd);
- curfile++;
- outopen();
- }
-
- closefile()
- {
- if (compress)
- pclose(fd);
- else
- fclose(fd);
- }
-
- validtime(s)
- char *s;
- {
- return (index(s,'.') != 0);
- }
-
- char *firstpart(s)
- char *s;
- {
- static char buf[64];
- strcpy(buf,s);
- *(index(buf,'.'))='\0';
- return buf;
- }
-
- char *lastpart(s)
- char *s;
- {
- return(index(s,'.')+1);
- }
-
-
- unsigned long hashval(s)
- char *s;
- {
- unsigned long v;
- int j;
-
- v=0;
- j=0;
- while (*s) {
- if (j>20)
- j=0;
- v += (*s++)<<(j++);
- }
- return v%HSIZE;
- }
-
-
- checkall()
- {
- clirec *c, *prev, *temp;
-
- c=pending;
- prev=NULL;
- while (c!=NULL) {
- if (tooold(c)) {
- emit(c);
- temp=c->nextpend;
- if (prev!=NULL) {
- prev->nextpend=c->nextpend;
- } else
- pending = c->nextpend;
- if (c->nextpend !=NULL)
- c->nextpend->prevpend = prev;
- remove(c); /* remove from parent list */
- free(c);
- c=temp;
- } else {
- prev=c;
- c=c->nextpend;
- }
- }
- }
-
- remove(c)
- clirec *c;
- {
- clirec *cl;
-
- cl=c->file->clients;
- if (cl==c) {
- c->file->clients = c->nextcli;
- return;
- }
- while (cl) {
- if (cl->nextcli == c) {
- cl->nextcli = c->nextcli;
- return;
- }
- cl=cl->nextcli;
- }
- }
-
-
- tooold(c)
- clirec *c;
- {
- return ((cursecs - c->lastsecs)>oplen);
- }
-
- readold(c)
- clirec *c;
- {
- if (c->writecount)
- return 0;
- return ((cursecs - c->lastsecs)>2);
- }
-
-
- file *getfile(s,h)
- char *s;
- char *h;
- {
- char buf[64];
- file *f;
- clirec *c;
- clirec *prev;
- clirec *temp;
- unsigned long hash;
-
- strcpy(buf,mkkey(s,h));
- hash=hashval(buf);
- f=table[hash];
- while (f!=NULL) {
- if (strcmp(f->key,buf)==0) {
- /* first we check for old clients */
- c=f->clients;
- prev=NULL;
- while (c) {
- if (tooold(c)) {
- emit(c);
- temp=c->nextcli;
- if (prev !=NULL)
- prev->nextcli = c->nextcli;
- else
- f->clients = c->nextcli;
- if (c->nextpend != NULL)
- c->nextpend->prevpend=
- c->prevpend;
- if (c->prevpend != NULL)
- c->prevpend->nextpend=
- c->nextpend;
- else
- pending=c->nextpend;
- free (c);
- c=temp;
- } else {
- prev=c;
- c=c->nextcli;
- }
- }
- return f;
- }
- f=f->next;
- }
- if ((f=(file *)Malloc(sizeof(file))) == NULL) {
- perror("malloc");
- exit(1);
- }
- nf++;
- if (nf>MAXNF)
- gc();
- strcpy(f->key,buf);
- f->mode=0;
- f->uid=0;
- f->size=0;
- f->clients=NULL;
- f->next=table[hash];
- table[hash]=f;
- return f;
- }
-
- clirec *getcli(f,n)
- file *f;
- char *n;
- {
- clirec *c;
-
- c=f->clients;
- while (c!=NULL) {
- if (strcmp(c->name,n)==0)
- return c;
- c=c->nextcli;
- }
- if ((c=(clirec *)Malloc(sizeof(clirec))) == NULL) {
- perror("malloc");
- exit(1);
- }
- strcpy(c->name,n);
- c->lastusecs=c->startusecs=curusecs;
- c->lastsecs=c->startsecs=cursecs;
- c->readcount=0;
- c->writecount=0;
- c->zeroaccessed=0;
- c->nextcli=f->clients;
- f->clients=c;
- c->nextpend=pending;
- if (pending !=NULL)
- pending->prevpend = c;
- c->prevpend = NULL;
- pending = c;
- c->file=f;
- return c;
- }
-
-
-
- char *mkkey(c,h)
- char *c;
- char *h;
- {
- static char buf[64];
-
- sprintf(buf,"%s:%s",c,h);
- return buf;
- }
-
-
- emit(c)
- clirec *c;
- {
- fprintf(fd,"%d.%06d | %s | %s | %s | %d | %d\n",
- c->startsecs,
- c->startusecs,
- (c->writecount?"write":"read"),
- c->file->key,
- c->name,
- (c->writecount?c->writecount:c->readcount),
- c->file->size?c->file->size:c->readcount);
- n++;
- }
-
- nfs_null()
- {
- /* do nothing */
- }
-
-
- nfs_getattr()
- {
- file *f;
- clirec *c;
- unsigned int mode;
-
- /* first, make sure this is a file */
- sscanf(l.reply.mode,"%o",&mode);
- if ((mode&S_IFMT) != S_IFREG)
- return;
- /* find or create a file record */
- if ((f=getfile(l.svr,l.call.handle1)) == NULL)
- exit(1); /* should never happen */
- /* set up the file values */
- f->uid = atoi(l.reply.uid);
- f->mode = mode;
- f->size = atoi(l.reply.size);
- if ((c=getcli(f,l.cln)) == NULL)
- exit(1); /* should never happen */
- c->lastsecs = cursecs;
- c->lastusecs = curusecs;
- }
-
- nfs_setattr()
- {
- /* do a little; this might really be a write */
- file *f;
- clirec *c;
- int size;
- int mode;
-
- size=atoi(l.reply.size);
- if (size<0)
- return;
- sscanf(l.reply.mode,"%o",&mode);
- if ((mode&S_IFMT) != S_IFREG)
- return;
- /* the size changed, so now we treat as a write */
- if ((f=getfile(l.svr,l.call.handle1)) == NULL)
- exit(1); /* should never happen */
- if ((c=getcli(f,l.cln)) == NULL)
- exit(1); /* should never happen */
- if ((c->readcount>0) ||
- readold(c)) { /* there was a read pending on this file */
- emit(c);
- c->startsecs=cursecs;
- c->startusecs=curusecs;
- c->readcount=0;
- c->zeroaccessed=0;
- }
- if (c->writecount && (size==0)) {
- emit(c);
- c->startsecs=cursecs;
- c->startusecs = curusecs;
- c->writecount=0;
- c->zeroaccessed = 0;
- }
- f->size=size;
- f->mode = mode;
- f->uid = atoi(l.reply.uid);
- c->writecount += 1;
- c->lastusecs=curusecs;
- c->lastsecs=cursecs;
- }
-
- nfs_root()
- {
- /* do nothing */
- }
-
- nfs_readlink()
- {
- /* do nothing */
- }
-
- nfs_read()
- {
- file *f;
- clirec *c;
- int count;
-
- if ((f=getfile(l.svr,l.call.handle1)) == NULL)
- exit(1); /* should never happen */
- if ((c=getcli(f,l.cln)) == NULL)
- exit(1); /* should never happen */
- if (c->writecount>0) { /* there was a write pending on this file */
- /* make sure this is a positive read */
- if (!(atoi(l.reply.count) < 0))
- return;
- emit(c);
- c->startsecs=cursecs;
- c->startusecs=curusecs;
- c->writecount=0;
- c->zeroaccessed=0;
- }
- if (atoi(l.call.offset)==0) {
- if (c->zeroaccessed) {
- emit(c);
- c->startsecs=cursecs;
- c->startusecs=curusecs;
- c->readcount=0;
- } else
- c->zeroaccessed=1;
- }
- c->readcount += atoi(l.reply.count);
- c->lastusecs=curusecs;
- c->lastsecs=cursecs;
- }
-
- nfs_writecache()
- {
- /* do nothing */
- }
-
-
- nfs_write()
- {
- file *f;
- clirec *c;
-
- if ((f=getfile(l.svr,l.call.handle1)) == NULL)
- exit(1); /* should never happen */
- if ((c=getcli(f,l.cln)) == NULL)
- exit(1); /* should never happen */
- if ((c->readcount>0) ||
- readold(c)) { /* there was a read pending on this file */
- emit(c);
- c->startsecs=cursecs;
- c->startusecs=curusecs;
- c->zeroaccessed=0;
- c->readcount=0;
- }
- if (atoi(l.call.offset)==0) {
- if (c->zeroaccessed) {
- emit(c);
- c->startsecs=cursecs;
- c->startusecs=curusecs;
- c->writecount=0;
- } else
- c->zeroaccessed=1;
- }
- c->writecount += atoi(l.call.count);
- f->size = atoi(l.reply.size);
- c->lastusecs=curusecs;
- c->lastsecs=cursecs;
- }
-
- nfs_creat()
- {
- /* do very little */
- }
-
- nfs_remove()
- {
- /* do very little */
- }
-
- nfs_rename()
- {
- /* do nothing */
- }
-
- nfs_lookup()
- {
- file *f;
- unsigned int mode;
-
- /* first, make sure this is a file */
- sscanf(l.reply.mode,"%o",&mode);
- if ((mode&S_IFMT) != S_IFREG)
- return;
- /* find or create a file record */
- if ((f=getfile(l.svr,l.reply.handle)) == NULL)
- exit(1); /* should never happen */
- /* set up the file values */
- f->uid = atoi(l.reply.uid);
- f->mode = mode;
- f->size = atoi(l.reply.size);
- }
-
- nfs_link()
- {
- /* do nothing */
- }
-
- nfs_symlink()
- {
- /* do nothing */
- }
-
- nfs_mkdir()
- {
- /* do nothing */
- }
-
- nfs_rmdir()
- {
- /* do nothing */
- }
-
- nfs_readdir()
- {
- /* do nothing */
- }
-
- nfs_statfs()
- {
- /* do nothing */
- }
-
- char *Malloc(n)
- int n;
- {
- char *m;
-
- if ((m=(char *)malloc(n)) == NULL) {
- gc();
- return ((char *)malloc(n));
- } else
- return (m);
- }
-
- gc()
- {
- int i;
- file *f;
- file **prev;
- int count=0;
-
- fprintf(fd,"#collecting garbage\n");
- fflush(fd);
- for (i=0; i<HSIZE; i++) {
- f=table[i];
- prev = &table[i];
- while (f != NULL) {
- if (f->clients == NULL) {
- *prev=f->next;
- free(f);
- f = *prev;
- count++;
- nf--;
- } else {
- prev = &f->next;
- f= f->next;
- }
- }
- }
- fprintf(fd,"#GC Count=%d\n",count);
- fflush(fd);
- }
-